<!DOCTYPE html>
<html lang="en" data-theme=""><head>
    <title> Rover | Roverliang Blog </title>

    
    <meta charset="utf-8"><meta name="generator" content="Hugo 0.79.1" /><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
    <meta name="description" content="代码如诗，生命如虹">
    
    <link rel="stylesheet"
          href="/css/style.min.39603a6316177eb06681d6e6ea0570fd106ead89cd6079055ca060feb76c7f83.css"
          integrity="sha256-OWA6YxYXfrBmgdbm6gVw/RBurYnNYHkFXKBg/rdsf4M="
          crossorigin="anonymous"
          type="text/css">
    
    <link rel="stylesheet"
        href="/css/markupHighlight.min.cc84ed683057cc175ddfa738ea6ba2d5c882b95cb64f50bf9be918cb3791887b.css"
        integrity="sha256-zITtaDBXzBdd36c46mui1ciCuVy2T1C/m&#43;kYyzeRiHs="
        crossorigin="anonymous"
        type="text/css">
    
    <link rel="stylesheet" 
    href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css" 
    integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA==" 
    crossorigin="anonymous" />

    
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">

    <link rel="canonical" href="/">

    
    <link rel="alternate" type="application/rss+xml" href="/index.xml" title="Roverliang Blog" />
    
    
    
    <script type="text/javascript"
            src="/js/anatole-header.min.d8599ee07b7d3f11bafbac30657ccc591e8d7fd36a9f580cd4c09e24e0e4a971.js"
            integrity="sha256-2Fme4Ht9PxG6&#43;6wwZXzMWR6Nf9Nqn1gM1MCeJODkqXE="
            crossorigin="anonymous"></script>


    
    <meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Roverliang Blog"/>
<meta name="twitter:description" content="代码如诗，生命如虹"/>


    

</head>
<body><div class="sidebar . ">
    <div class="logo-title">
        <div class="title">
            <img src="/images/wx_avatar.jpeg" alt="profile picture">
            <h3 title=""><a href="/">I&#39;m Rover</a></h3>
            <div class="description">
                <p>代码如诗，生命如虹</p>
            </div>
        </div>
    </div>
    <ul class="social-links">
        
    </ul>
    <div class="footer">
        <div class="by_farbox">&copy; Rover  2020-2021 </div>
    </div>
</div>
<div class="main">
    <div class="page-top  . ">
    <a role="button" class="navbar-burger" data-target="navMenu" aria-label="menu" aria-expanded="false">
        <span aria-hidden="true"></span>
        <span aria-hidden="true"></span>
        <span aria-hidden="true"></span>
    </a>
    <ul class="nav" id="navMenu">
        
        
            
            <li><a class="current"
                   href="/"
                        
                   title="">Home</a></li>
        
        
        
    </ul>
</div>

    <div class="autopagerize_page_element">
        <div class="content">

    <div class="post  . ">
        
        
    </div>

    
    

        <div class="post  . ">
            
            <div class="post-title">
                <h3><a href="/posts/context/">context 标准库</a>
                </h3>
            </div>
            <div class="post-content">
                <div class="p_part">
                    <p>注：本文参考摘抄于《Go语言核心编程》
 Go 中的goroutine 之间并没有父与子的关系，也就是没有所谓子进程退出后的通知机制，多个goroutine都是平行地被调度，多个goroutine如何协作设计通信、同步、通知和退出四个方面。
通信： chan通道当然是goroutine 之间通信的基础。注意这里的通信主要是指程序的数据通信。
同步: 不带缓冲的chan提供了一个天然的同步等待机制；当然sync.WaitGroup也为多个goroutine协同工作提供一种同步等待机制。
通知： 这个通知和上面通信的数据不一样，通知通常不是业务数据，而是管理、控制流数据。要处理这个也有方法，在输入端绑定两个chan，一个用于业务流数据，另一个用于异常通信数据，然后使用select收敛进行处理。这个方案可以解决简单的问题，但不是一个通用的解决方案。
退出: goroutine 之间没有父子关系，如何通知goroutine退出？可以通过增加一个单独的通道，借助通道和select的广播机制（close channel to broadcast） 实现退出。
Go 语言在语法上处理某个goroutine退出通知机制很简单。但是遇到复杂的并发结构处理起来就显得力不从心。实际编程中goroutine会拉起新的goroutine，新的goroutine又会拉起另外一个新的goroutine，最终形成一个树状的结构。由于goroutine里并没有父子概念，这个树状结构知识在程序员头脑中抽象出来的，程序的执行模型并没有维护这么一个树状结构。
怎么通知这个树状上所有的goroutine退出？仅依靠语法层面的支持显然比较难处理。为此Go1.7 提供了一个标准库context来解决这个问题。它提供两种功能：退出通知和 元数据传递。context库的设计目的就是跟踪goroutine调用，在其内部维护一个调用树。并在这些调用树中传递通知和元数据。
一、context 的设计目的 context库的目的就是跟踪goroutine的调用树，并在这些goroutine 调用树中传递通知和元数据。两个目的：
 退出通知机制 —— 通知可以传递给整个goroutine调用树上的每一个goroutine。 传递数据—— 数据可以传递给整个goroutine调用树上的goroutine。  二、基本数据结构 在介绍context包之前，先理解context包的整体工作机制：
第一个创建Context 的goroutine 被称之为root节点。
root节点负责创建一个实现Context接口的具体对象，并将该对象作为参数传递到其新拉起的goroutine中，下有的goroutine可以继续封装该对象，再传递到更下游的goroutine。
Context对象在传递的过程中最终形成一个树状的数据结构，这样通过位于root节点（树的根节点）的Context对象就能遍历整个Context 对象树，通知和消息就可以通过root节点传递出去。实现了上游goroutine 对下游goroutine 的消息传递。
Context 接口 Context 是一个基本接口，所有的Context 对象都要实现该接口，context 的使用者在调用接口中都使用Context 作为参数类型。
type Context interface { //如果Context实现了超时控制，则该方法返回ok true, deadline 为超时时间。 	Deadline() (deadline time.Time, ok bool) //后端被调用的goroutine应该监听该方法返回的chan，以便及时释放资源 	Done() &lt;-chan struct{} //Done 返回的chan 收到通知的时候，才可以访问Err() 获知为什么原因被取消 	Err() error //可以访问上游goroutine传递给下游goroutine 的值。 	Value(key interface{}) interface{} } canceler 接口 canceler 接口是一个扩展接口，规定了取消通知的Context具体类型需要实现的接口。context包中的具体类型*cancelCtx 和*timeCtx 都实现了该接口。如下：</p>
                    </div>
            </div>

            
            <div class="post-footer">
                <div class="meta">
                    <div class="info">
                        <em class="fas fa-calendar-day"></em>
                            <span class="date"> Wed, Sep 9, 2020
                                             </span>
                        
                        
                    </div>
                </div>
            </div>
        </div>
    
    <div class="pagination">
        


    </div>

        </div>
    </div>
</div>

<script type="text/javascript"
        src="/js/medium-zoom.min.92f21c856129f84aeb719459b3e6ac621a3032fd7b180a18c04e1d12083f8aba.js"
        integrity="sha256-kvIchWEp&#43;ErrcZRZs&#43;asYhowMv17GAoYwE4dEgg/iro="
        crossorigin="anonymous"></script></body>

</html>
